package dungeonElements;

import be.kuleuven.cs.som.annotate.Raw;
import temperature.Temperature;
import dungeonTools.Direction;

/**
 * A class of TransparentSquares.
 * 
 * @invar A TransparenSquare always has proper borders. This means:
 * 		-There aren't any walls set as border
 * 		-No more than 2 doors can be placed at a given time
 * 		-If 2 doors are placed, their at opposite directions of the square
 * 		|hasProperBorders()
 * 
 * @author Tom Jacobs & Ewoud De Moor
 * @version 3.0
 */
public class TransparentSquare extends TeleportationSquare {

	/**
	 * Creates a new transparent square with the given temperature and humidity.
	 * A Door will be set in the given direction. The boolean value then decides
	 * whether or not another door will be placed. This door automatically comes
	 * at the opposite direction of the first door.
	 * 
	 * @param temperature
	 * 			The temperature to set this new transparent square to
	 * @param humidity
	 * 			The humidity to set this new transparent square to
	 * @param doorDirection
	 * 			The direction in which a door will be placed
	 * @param oppositeDirectionHasDoor
	 * 			Decides whether or not the opposite direction of the given one
	 * 			will hold a door as well
	 * @effect	Creates a new TeleportationSquare with the given temperature and humidity
	 * 			|super(temperature,humidity,false,false,false,false,false,false)
	 * @effect	Builds a door in the direction
	 * 			|buildDoor(doorDirection)
	 * @effect	Builds a door in the opposite direction if required
	 * 			|if(oppositeDirectionHasDoor)
	 * 			|	then buildDoor(doorDirection.getOppositeDirection())
	 */
	@Raw
	public TransparentSquare(Temperature temperature, double humidity, Direction doorDirection, boolean oppositeDirectionHasDoor){
		super(temperature,humidity,false,false,false,false,false,false);
		buildDoor(doorDirection);
		if(oppositeDirectionHasDoor)
			buildDoor(doorDirection.getOppositeDirection());
		initializationDone = true;
	}
	
	private boolean initializationDone = false;
	
	
	/**
	 * Check whether this TransparentSquare can have the given border in the given direction 
	 * as its border.
	 * 
	 * @param border
	 * 		The border to check
	 * @param direction
	 * 		The direction to check
	 * @return False if direction is not initialized
	 * 		| if(direction == null)
	 * 		|	then result == false
	 * @return True if this TransparentSquare is terminated and the border is set to nothing.
	 * 		| if(this.isTerminated && (border==null))
	 * 		|	then result == true
	 * @return False if the given border is a terminated border
	 * 		| if( (border!=null) && border.isTerminated())
	 * 		|	then result == false
	 * @return True if setting the border wouldn't change anything.
	 * 		| if( (getBorder(direction) != null && getBorder(direction).equals(border))
	 *		|		|| ((getBorder(direction)==null)&&(border==null)) )
	 * 		|	then result == true
	 * @return False if a TransparentSquare can't have the given border in the given direction.
	 * 		| if(!super.canHaveAsBorderInDirection(border, direction))
	 * 		|	then result == false
	 * @return False if the transparent square will have an invalid Door setup, True otherwise
	 * 		|int countBorders = 0;
	 *		|int countDoors = 0;
	 *		|for(Direction allDirections : Direction.values()){
	 *		|	if(hasBorderInDirection(allDirections)){
	 *		|		countBorders++;
	 *		|		if( getBorder(allDirections) instanceof Door ){
	 *		|			countDoors++;
	 *		|		}
	 *		|	}
	 *		|}
	 *		False if the square would end without borders
	 *		|if( (countBorders<=1) && (border==null) ) {
	 *		|	if(countBorders==0)
	 *		|		result == false
	 *		|	if( hasBorderInDirection(direction) )
	 *		|		result == false
	 *		|}
	 *		False a door would be set at another location than the current door or his opposite direction
	 *		|if((countDoors == 1) && (getBorder(direction) == null) && (getBorder(direction.getOppositeDirection()) == null))
	 *		|	result == false
	 *		False if the Door isn't placed at one of the 2 current doors
	 *		|if((countDoors == 2) && (((getBorder(direction)) != null) || (getBorder(direction.getOppositeDirection()) != null)))
	 *		|	result == false
	 *		True otherwise
	 *		|result == true
	 */
	@Override @Raw
	public boolean canHaveAsBorderInDirection(Border border, Direction direction) {
		if(direction == null)
			return false; //Direction not initialized
		if( this.isTerminated() && (border==null) )
			return true;
		if( (border!=null) && border.isTerminated())
			return false; //Can not have a terminated border
		if( (getBorder(direction) != null && getBorder(direction).equals(border))
				|| ((getBorder(direction)==null)&&(border==null)) )
			return true; //Current state
		
		if(!super.canHaveAsBorderInDirection(border, direction))
			return false; //Needed to check for doors between squares of a shaft
		
		int countBorders = 0;
		int countDoors = 0;
		for(Direction allDirections : Direction.values()){
			//Count borders and doors
			if(hasBorderInDirection(allDirections)){
				countBorders++;
				if( getBorder(allDirections) instanceof Door ){
					countDoors++;
				}
			}
		}
		if( (countBorders<=1) && (border==null) ) {
			if(countBorders==0)
				return false; //Would result in no borders
			if( hasBorderInDirection(direction) )
				return false; //Would result in no borders
		}
		assert countBorders == countDoors;
		assert countDoors <= 2;
		if((countDoors == 1) && (getBorder(direction) == null) && (getBorder(direction.getOppositeDirection()) == null))
			return false;
		if((countDoors == 2) && (((getBorder(direction)) != null) || (getBorder(direction.getOppositeDirection()) != null)))
			return false;
		return true;
	}

	/**
	 * Check whether this TransparentSquare has proper borders.
	 * 
	 * @return False if this TeleportaionSquare hasn't proper borders
	 * 		| if(!super.hasProperBorders())
	 * 		|	then result == false
	 * @return False if this method would return that when called on a TeleportationSquare
	 * 		|if(!super.hasProperBorders())
	 * 		|	result == false
	 * @return False if the transparent square has an invalid door setup, true otherwise
	 * 		|int countBorders = 0;
	 * 		|int countDoors = 0;
	 * 		|for(Direction allDirections : Direction.values()){
	 * 		|	if( !hasProperBorderInDirection(allDirections))
	 * 		False if there isn't a proper border in one of the directions
	 * 		|		return false;
	 * 		|	if(hasBorderInDirection(allDirections)){
	 * 		|		countBorders++;
	 * 		|		if( getBorder(allDirections) instanceof Door ){
	 * 		|			countDoors++;
	 * 		|			doorDirection = allDirections;
	 * 		|		}
	 * 		|	}
	 * 		|}
	 * 		False if there isn't a direction set with a door
	 * 		|if(doorDirection == null)
	 * 		|	return false;
	 * 		False if there are more than 2 doors
	 * 		|if(countDoors > 2)
	 * 		|	return false;
	 * 		False if there are other borders than doors set
	 * 		|if(countBorders != countDoors)
	 * 		|	return false;
	 * 		False if the door isn't set in the correct direction
	 * 		|if((countDoors == 1) && (getBorder(doorDirection.getOppositeDirection()) instanceof Door))
	 * 		|	return false;
	 * 		False if the 2 doors aren't set in opposite directions
	 * 		|if((countDoors == 2) && !(getBorder(doorDirection.getOppositeDirection()) instanceof Door))
	 * 		|	return false;
	 * 		True otherwise
	 * 		|return true;	
	 */
	@Override @Raw
	public boolean hasProperBorders() {
		if(!initializationDone)
			return true;
		if(!super.hasProperBorders())
			return false; //Needed to check for doors between squares of a shaft
		Direction doorDirection = null;
		int countBorders = 0;
		int countDoors = 0;
		for(Direction allDirections : Direction.values()){
			if( !hasProperBorderInDirection(allDirections))
				return false;
			//Count borders and doors
			if(hasBorderInDirection(allDirections)){
				countBorders++;
				if( getBorder(allDirections) instanceof Door ){
					countDoors++;
					doorDirection = allDirections;
				}
			}
		}
		//Check counters
		if(doorDirection == null)
			return false;
		if(countDoors > 2)
			return false;		
		if(countBorders != countDoors)
			return false;
		if((countDoors == 1) && (getBorder(doorDirection.getOppositeDirection()) instanceof Door))
			return false;
		if((countDoors == 2) && !(getBorder(doorDirection.getOppositeDirection()) instanceof Door))
			return false;
		return true;	
	}
}
